use crate::{abstractions::{data::Data, portable_task::TaskPortableAbs, task::TaskAbstraction}, error::ServerError, protocol::{task::SymbolicTask, type_schema::TypeSchema}};
use crate::abstractions::portable_fuse::fuse;
use crate::protocol::type_derive::FuseDirection;
use std::sync::{Arc, Mutex};
use serde::Serialize;
pub type RunningWorkflowId = String;
pub type RunningTaskId = String;

#[derive(Clone, Debug, Serialize)]
pub enum WorkflowRunningStatus {
    Created,
    Running(usize), // 运行到第几个任务
    Finished,
    Failed(String),
}

impl WorkflowRunningStatus {
    pub fn idx(&self) -> usize {
        match self {
            WorkflowRunningStatus::Running(v) => *v,
            _ => unreachable!()
        }
    }
    pub fn is_not_finished(&self) -> bool {
        match self {
            WorkflowRunningStatus::Created => true,
            WorkflowRunningStatus::Running(_) => true,
            _ => false
        }
    }
    pub fn completed(&self) -> bool {
        match self {
            WorkflowRunningStatus::Finished => true,
            WorkflowRunningStatus::Failed(_) => true,
            _ => false
        }
    }
}

pub enum Workflow {
    Static(String, TypeSchema, TypeSchema, Vec<Arc<TaskAbstraction>>, Vec<(FuseDirection, bool)>),
    // Running(String, RunningWorkflowId, TypeSchema, TypeSchema, Vec<Arc<TaskAbstraction>>, Vec<RunningTaskId>, WorkflowRunningStatus, Arc<Mutex<bool>>),
    ChainPortable(TaskPortableAbs, String)
}

use Workflow::*;

impl Workflow {
    pub fn into_portable(self) -> Result<Workflow, ServerError> {
        match self {
            Static(name, tin, tout, tasks, fuse_config) => {
                let mut fused: TaskPortableAbs;
                let mut err = false;
                if tasks.len() == 0 {
                    return Err(ServerError::WorkflowError(format!("工作流 {} 没有任务", name)));
                }
                fused = TaskPortableAbs::from_taskabs(tasks[0].clone())?;
                for i in 1..tasks.len() {
                    let task = TaskPortableAbs::from_taskabs(tasks[i].clone())?;
                    match fuse_config[i].0 {
                        FuseDirection::Positive => {
                            match fuse(&fused, &task, fuse_config[i].1) {
                                Some(res) => fused = res,
                                None => { eprintln!("workflow fuse error: {:?}, {:?}, {:?}", &fused.sig(), task.sig(), fuse_config[i]); err = true; break }
                            }
                        }
                        FuseDirection::Negative => {
                            match fuse(&task, &fused, fuse_config[i].1) {
                                Some(res) => fused = res,
                                None => { eprintln!("workflow fuse error: {:?}, {:?}, {:?}", task.sig(), &fused.sig(), fuse_config[i]); err = true; break }
                            }
                        }
                        FuseDirection::Equal => return Err(ServerError::WorkflowErrorStr("invalid fuse_config: Equal")),
                    }
                }
                if err {
                    Err(ServerError::WorkflowErrorStr("workflow fuse error"))
                } else {
                    Ok(ChainPortable(fused, name))
                }
            }
            _ => unreachable!()
        }
    }
    pub fn name(&self) -> &String {
        match self {
            Static(name, _, _, _, _) => name,
            // Running(name, _, _, _, _, _, _, _) => name,
            ChainPortable(_, name) => name,
        }
    }
    pub fn tin(&self) -> &TypeSchema {
        match self {
            Static(_, tin, _, _, _) => tin,
            // Running(_, _, tin, _, _, _, _, _) => tin,
            ChainPortable(t, _) => t.tin(),
        }
    }
    pub fn tout(&self) -> &TypeSchema {
        match self {
            Static(_, _, tout, _, _) => tout,
            // Running(_, _, _, tout, _, _, _, _) => tout,
            ChainPortable(t, _) => t.tout(),
        }
    }
    pub fn as_running(&self, id: RunningWorkflowId) -> Workflow {
        match self {
            Static(name, tin, tout, tasks, fuse_directions) => {
                // Running(name.clone(), id, tin.clone(), tout.clone(), tasks.clone(), vec![], WorkflowRunningStatus::Created, Arc::new(Mutex::new(false)))
                todo!()
            },
            _ => unreachable!()
        }
    }
    pub fn terminate_flag(&self) -> Arc<Mutex<bool>> {
        match self {
            // Running(_, _/, _, _, _, _, _, flag) => flag.clone(),
            _ => unreachable!()
        }
    }
    pub fn sig(&self) -> SymbolicTask {
        SymbolicTask::new(self.name().clone(), self.tin().clone(), self.tout().clone())
    }
    pub fn rename(self, name: String) -> Self {
        match self {
            Static(_, tin, tout, tasks, fuse_directions) => Static(name, tin, tout, tasks, fuse_directions),
            _ => unreachable!()
        }
    }
}

#[derive(Debug, Serialize, Clone)]
pub struct RunningWorkflow {
    pub port: u16,
    pub name: String,
    pub status: WorkflowRunningStatus,
    pub progress: Vec<(String, u64)>,
    pub created_at: u64,
    pub completed_at: Option<u64>,
    pub result: Option<String>,
}
